﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Jinjia.Approve.Common.Extensions;
using Jinjia.Approve.Entity.Entity;
using Jinjia.Approve.IService.JJFlow;
using Jinjia.Approve.IService.JJFlow.Action;
using Jinjia.Approve.Model.Input.JJFlow;
using Jinjia.Approve.Model.VM;
using Jinjia.Approve.Model.VM.JJFlow;
using Jinjia.Approve.Model.VM.JJFlow.DTO;
using Jinjia.Core.Attribute;
using JinJia.Core.Base.Exceptions;
using Jinjia.Core.BaseInfrastructure.BaseModel.BaseModel;
using Jinjia.Core.BaseInfrastructure.StorageModel.Model;
using Microsoft.AspNetCore.Http;
using Jinjia.Approve.Model.VM.JJFlow.Request;
using Jinjia.Approve.IRepository;
using Jinjia.Approve.IRepository.JJFlow;
using Jinjia.Approve.Model.Config;
using Jinjia.Approve.Model.Const;
using Jinjia.Approve.Model.Enum;
using Jinjia.Approve.Model.VM.JJFlow.FeiShu;
using Jinjia.Approve.Model.VM.OA;
using Jinjia.Core.BaseInfrastructure.StorageModel;
using Jinjia.Core.BaseInfrastructure.StorageModel.RepositoryBase;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using MySqlX.XDevAPI.Common;

namespace Jinjia.Approve.Service.JJFlow
{
    public class JJFlowService : JJFlowCommonService, IJJFlowService
    {
        private readonly IErpaUserRepository _erpaUserRepository;
        private readonly IJJFLowActionCreate _jjfLowActionCreate;
        private readonly IJJFLowActionApprove _jjfLowActionApprove;
        private readonly IJJFLowActionReject _jjfLowActionReject;
        private readonly IJJFLowActionRecall _jjfLowActionRecall;
        private readonly IJJFLowActionCommon _jjfLowActionCommon;
        private readonly IJJFlowActionPassOn _jjFlowActionPassOn;
        private readonly IJJFLowActionCopy _jjfLowActionCopy;
        private readonly IJJFlowActionSendBack _jjFlowActionSendBack;
        private readonly IJJFlowNodeService _jJFlowNodeService;
        private readonly IJJFlowTemplateService _jjFlowTemplateService;
        private readonly IJJFlowInstanceService _jjFlowInstanceService;
        private readonly IJJFlowNodeReferenceService _jjFlowNodeReferenceService;
        private readonly IJJFlowInstanceEmpService _jjFlowInstanceEmpService;
        private readonly IRepositoryBase<erpa_function_tbl> _functionRepository;
        private readonly IJJFlowDicCodeService _jjFlowDicCodeService;
        private readonly IFlowInstanceFormRepository _jjFlowInstanceFormRepository;
        private readonly IConfiguration _configuration;
        private readonly HttpClient _openApiHttpClient;
        private readonly IFlowInstanceEmpBakRepository _flowInstanceEmpBakRepository;
        private readonly IJJFlowTrackService _jjFlowTrackService;

        public JJFlowService(IHttpContextAccessor httpContextAccessor,
            IErpaUserRepository erpaUserRepository,
            IJJFlowClientService jjFlowClientService,
            IJJFLowActionCreate jjfLowActionCreate,
            IJJFLowActionApprove jjfLowActionApprove,
            IJJFLowActionReject jjfLowActionReject,
            IJJFLowActionCommon jjfLowActionCommon,
            IJJFLowActionRecall jjfLowActionRecall,
            IJJFlowActionPassOn jjFlowActionPassOn,
            IJJFLowActionCopy jjfLowActionCopy,
            IJJFlowActionSendBack jjFlowActionSendBack,
            IJJFlowNodeService jJFlowNodeService,
            IJJFlowTemplateService jjFlowTemplateService,
            IJJFlowInstanceService jjFlowInstanceService,
            IJJFlowNodeReferenceService jjFlowNodeReferenceService,
            IJJFlowInstanceEmpService jjFlowInstanceEmpService,
            IRepositoryBase<erpa_function_tbl> functionRepository,
            IJJFlowDicCodeService jjFlowDicCodeService,
            IFlowInstanceFormRepository jjFlowInstanceFormRepository,
            IConfiguration configuration,
            IOptions<UrlConfigOption> urlConfigOption,
            IHttpClientFactory httpClientFactory,
            IFlowInstanceEmpBakRepository flowInstanceEmpBakRepository,
            IJJFlowTrackService jjFlowTrackService) : base(httpContextAccessor,
            jjFlowClientService)
        {
            _erpaUserRepository = erpaUserRepository;
            _jjfLowActionCreate = jjfLowActionCreate;
            _jjfLowActionApprove = jjfLowActionApprove;
            _jjfLowActionReject = jjfLowActionReject;
            _jjfLowActionRecall = jjfLowActionRecall;
            _jjfLowActionCommon = jjfLowActionCommon;
            _jjFlowActionPassOn = jjFlowActionPassOn;
            _jjfLowActionCopy = jjfLowActionCopy;
            _jjFlowActionSendBack = jjFlowActionSendBack;
            _jJFlowNodeService = jJFlowNodeService;
            _jjFlowTemplateService = jjFlowTemplateService;
            _jjFlowInstanceService = jjFlowInstanceService;
            _jjFlowNodeReferenceService = jjFlowNodeReferenceService;
            _jjFlowInstanceEmpService = jjFlowInstanceEmpService;
            _functionRepository = functionRepository;
            _jjFlowDicCodeService = jjFlowDicCodeService;
            _jjFlowInstanceFormRepository = jjFlowInstanceFormRepository;
            _configuration = configuration;
            _flowInstanceEmpBakRepository = flowInstanceEmpBakRepository;
            _jjFlowTrackService = jjFlowTrackService;
            var urlConfig = urlConfigOption.Value;
            _openApiHttpClient = httpClientFactory.CreateClient("ISP");
            _openApiHttpClient.BaseAddress = new Uri($"{urlConfig.GatewayUrl.TrimEnd('/')}/{urlConfig.ServiceName.FirstOrDefault(x => x.Key == "Isp").Value}/");
            _openApiHttpClient.DefaultRequestHeaders.Add("Token", urlConfig.AccessToken);
            _generateTasksFuncDict = new Dictionary<string, Func<JjFlowInstanceVM, JJFlowNodeReferenceVM, List<JJFlowNodeReferenceVM>, List<EmpInfo>, string, string, Task<List<FeiShuTripartiteTask>>>>
            {
                { JJFlowInstanceStatusConst.Pending, GenerateTasksWhenPending },
                { JJFlowInstanceStatusConst.Reject, GenerateTasksWhenReject },
                { JJFlowInstanceStatusConst.Approved, GenerateTasksWhenApproved },
                { JJFlowInstanceStatusConst.Recall, GenerateTasksWhenRecall }
            };
        }

        [UseTran]
        public virtual async Task<NodeInfo> Create(CreateRequest request)
        {
            RequestUserIdChecker(request);
            var template_id = await TemplateByModularKeyChecker(request.modular_key);
            var result = await _jjfLowActionCreate.Create(request.modular_key, template_id, request.biz_order_id, request.user_id, request.form);
            //执行自动审核规则
            result = await AutoApproveRule(request, result);
            return result;
        }

        /// <summary>
        /// 自动审核规则
        /// </summary>
        /// <param name="request"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        private async Task<NodeInfo> AutoApproveRule(CreateRequest request, NodeInfo result)
        {
            if (result.info != null && result.info.data.auto_approve == 1)
            {
                //解析驳回规则
                if (await _jJFlowNodeService.CheckConditionNew(result.instance_id, result.info.data.reject_rule))
                {
                    request.user_id = result.emp_user.FirstOrDefault().user_id;
                    request.remark = "满足自动驳回条件，自动驳回";
                    await Reject(request);
                    result.info.data.auto_approve = 0;
                }
                //解析通过规则
                else if (await _jJFlowNodeService.CheckConditionNew(result.instance_id, result.info.data.approve_rule))
                {
                    request.user_id = result.emp_user.FirstOrDefault().user_id;
                    request.remark = "满足自动通过条件，自动同意";
                    result = await Approve(request);
                }
            }

            return result;
        }

        [UseTran]
        public virtual async Task<NodeInfo> Approve(CreateRequest request)
        {
            RequestUserIdChecker(request);
            var template_id = await TemplateByModularKeyChecker(request.modular_key);
            var template = await _jjFlowTemplateService.GetTemplateDetail(template_id);
            var instance_info = await InstanceInfoChecker(request.modular_key, request.biz_order_id);
            var result = await _jjFlowClientService.Approve(instance_info.Id, request.user_id, request.remark, request.is_auto_approve);
            result.instance_id = instance_info.Id;
            if (result.info == null)
            {
                return result;
            }

            //全局自动通过优先
            if (template.is_auto_approve == 1)
            {
                //当前节点待审核人包含上个节点已审核人，则直接通过
                instance_info = await InstanceInfoChecker(request.modular_key, request.biz_order_id);
                //历史所有已审核的节点
                var historyApprover = await _jjfLowActionApprove.GetReviewedUser(0, instance_info.Id, template_id, 1);
                if (historyApprover.Any() && instance_info.CurrentNodeId != result.info.data.id)
                {
                    var currentApprover = result.emp_user.FirstOrDefault(x => historyApprover.Select(y => y.user_id).Contains(x.user_id));
                    if (currentApprover != null)
                    {
                        request.user_id = currentApprover.user_id;
                        request.remark = "自动同意";
                        result = await Approve(request);
                    }
                }
            } //相邻节点自动审核
            else if (result.info.data.auto_approve == 1)
            {
                //当前节点待审核人包含上个节点已审核人，则直接通过
                instance_info = await InstanceInfoChecker(request.modular_key, request.biz_order_id);
                var prev_approver = await _jjfLowActionApprove.GetReviewedUser(instance_info.CurrentNodeId, instance_info.Id, template_id, 1);
                if (prev_approver.Count > 0 && instance_info.CurrentNodeId != result.info.data.id)
                {
                    var current_approver = result.emp_user.Where(x => prev_approver.Select(y => y.user_id).Contains(x.user_id)).FirstOrDefault();
                    if (current_approver != null)
                    {
                        request.user_id = current_approver.user_id;
                        request.remark = "自动同意";
                        result = await Approve(request);
                    }
                }
            }

            //执行自动审核规则
            result = await AutoApproveRule(request, result);

            return result;
        }

        [UseTran]
        public virtual async Task<int?> AutoApprove(AutoApproveRequest request)
        {
            var instance_emp = await _jjfLowActionApprove.GetInstanceEmp(request.biz_order_id, request.modular_key);
            var approve_request = new CreateRequest();
            foreach (var item in instance_emp)
            {
                approve_request.user_id = item.user_id;
                approve_request.biz_order_id = request.biz_order_id;
                approve_request.modular_key = request.modular_key;
                approve_request.is_auto_approve = 1;
                await Approve(approve_request);
            }

            return instance_emp.LastOrDefault()?.instance_id;
        }

        [UseTran]
        public virtual async Task<int> Reject(CreateRequest request)
        {
            RequestUserIdChecker(request);
            var template_id = await TemplateByModularKeyChecker(request.modular_key);
            var instance_info = await InstanceInfoChecker(request.modular_key, request.biz_order_id);
            await _jjfLowActionReject.Reject(instance_info.Id, request.user_id, request.remark);
            return instance_info.Id;
        }

        [UseTran]
        public virtual async Task<int> Recall(ReCallRequest request)
        {
            RequestUserIdChecker(request);
            var template_id = await TemplateByModularKeyChecker(request.modular_key);
            var instance_info = await InstanceInfoChecker(request.modular_key, request.biz_order_id);
            await _jjfLowActionRecall.ReCall(instance_info.Id, request.user_id);
            return instance_info.Id;
        }

        [UseTran]
        public virtual async Task<List<JjFlowTrackVM>> GetFlowTrackList(CreateRequest request)
        {
            BizOrderIdChecker(request.biz_order_id);
            await TemplateByModularKeyChecker(request.modular_key);
            var jjFlowTrackVms = await _jjfLowActionCommon.GetFlowTrackList(request.biz_order_id, request.modular_key);
            return jjFlowTrackVms;
        }

        [UseTran]
        public virtual async Task<List<EmpInfo>> GetCompletedNodeList(CreateRequest request)
        {
            BizOrderIdChecker(request.biz_order_id);
            await TemplateByModularKeyChecker(request.modular_key);
            var instance_info = await _jjFlowClientService.GetInstanceInfo(request.modular_key, request.biz_order_id);
            if (instance_info == null)
            {
                return default;
            }

            var jjFlowTrackVms = await _jjfLowActionCommon.GetCompletedNodeList(instance_info);
            return jjFlowTrackVms;
        }

        [UseTran]
        public virtual async Task<string> ViewedLog(CreateRequest request)
        {
            if (string.IsNullOrWhiteSpace(request.biz_order_id) || string.IsNullOrWhiteSpace(request.doc_model))
            {
                throw new BusinessException("业务ID或者模块ID不能为空！");
            }

            var result = await _jjfLowActionCommon.RecordViewLog(request.doc_model, request.biz_order_id, GetUserId());

            if (result == 0)
            {
                return "记录失败！";
            }
            else
            {
                return "Success!";
            }
        }

        public async Task<List<ErpaViewedLogViewModel>> GetViewedLog(CreateRequest request)
        {
            if (string.IsNullOrWhiteSpace(request.biz_order_id) || string.IsNullOrWhiteSpace(request.doc_model))
            {
                throw new BusinessException("业务ID或者模块ID不能为空！");
            }

            var result = await _jjfLowActionCommon.GetViewedLog(request.doc_model, request.biz_order_id);
            return result;
        }


        [UseTran]
        public virtual async Task<ResponseResult<string>> CopyJJFlowTrack(CopyJJFlowRequest request)
        {
            if (string.IsNullOrWhiteSpace(request.biz_order_id) || string.IsNullOrWhiteSpace(request.biz_order_id_destination))
            {
                throw new BusinessException("业务ID不能为空！");
            }

            var template_id = await TemplateByModularKeyChecker(request.modular_key);
            //获取所有申请记录
            var instance_list = await _jjfLowActionCopy.GetInstanceList(request.modular_key, request.biz_order_id);
            if (instance_list == null)
            {
                return new ResponseResult<string>()
                {
                    IsSuccess = false,
                    Message = "未找到申请记录！"
                };
            }

            if (instance_list.Any(x => x.EndNodeId == x.CurrentNodeId) == false)
            {
                throw new BusinessException("审批未完成单据不可复制");
            }


            await _jjfLowActionCopy.Copy(instance_list, template_id, request.biz_order_id_destination);
            return new ResponseResult<string>()
            {
                IsSuccess = true,
                Message = "复制成功！"
            };
        }

        [UseTran]
        public virtual async Task<bool> GetUserPower(QueryRequest request)
        {
            RequestUserIdChecker(request);
            var hasPower = await _jjfLowActionApprove.GetUserPower(request.system_key, request.big_modular_key, request.modular_key, request.user_id);
            return hasPower;
        }

        [UseTran]
        public virtual async Task<List<string>> GetUserBizOrderId(QueryRequest request)
        {
            RequestUserIdChecker(request);
            return await _jjFlowClientService.GetUserBizOrderId(request);
        }

        public async Task<PageListSearchResultVM<MyTodoListOverview>> GetMyTodoList(SearchConditionBaseInput input)
        {
            return await _jjFlowClientService.GetMyTodoListOverview(GetUserId(), input);
        }

        public async Task<int> GetMyTodoListCount()
        {
            return await _jjFlowClientService.GetMyTodoListCount(GetUserId());
        }


        public async Task<PageListSearchResultVM<MyTodoListDetail>> GetTodoListDetailForCurrentUser(GetToDoListDetailByTab input)
        {
            return await _jjFlowClientService.GetTodoListDetailForCurrentUser(GetUserId(), input);
        }

        public async Task<IReadOnlyList<SearchByUrlResponse>> SearchByUrl(string url)
        {
            return await _jjFlowClientService.SearchByUrl(url);
        }


        [UseTran]
        public virtual async Task<List<string>> GetUserProcessedBizOrderId(QueryRequest request)
        {
            RequestUserIdChecker(request);
            var userProcessedBizOrderId = await _jjfLowActionApprove.GetUserProcessedBizOrderId(request.system_key, request.big_modular_key, request.modular_key, request.user_id);
            return userProcessedBizOrderId;
        }

        [UseTran]
        public virtual async Task<List<string>> GetUserCreateApplyBizOrderId(QueryRequest request)
        {
            RequestUserIdChecker(request);
            var userCreateApplyBizOrderId = await _jjfLowActionApprove.GetUserCreateApplyBizOrderId(request.system_key, request.big_modular_key, request.modular_key, request.user_id);
            return userCreateApplyBizOrderId;
        }

        [UseTran]
        public virtual async Task<bool> PassOn(PassOnRequest request)
        {
            var instanceId = 0;
            if (request.biz_order_id > 0 && !string.IsNullOrWhiteSpace(request.modular_key))
            {
                var instanceInfo = await InstanceInfoChecker(request.modular_key, request.biz_order_id.ToString());
                instanceId = instanceInfo.Id;
            }

            await _jjFlowActionPassOn.PassOn(request, instanceId, GetUserId());
            return true;
        }

        public async Task<bool> TransferFlowsAsync(TransferFlowsInput input)
        {
            return await _jjFlowActionPassOn.TransferFlowsAsync(input.InstanceEmpIds, input.HandoverUserId, GetUserId());
        }

        public async Task<NodeInfo> SendBack(SendBackRequest request)
        {
            if (request == null || request.biz_order_id < 1 || string.IsNullOrWhiteSpace(request.modular_key))
            {
                throw new BusinessException("参数有误");
            }

            var instanceInfo = await InstanceInfoChecker(request.modular_key, request.biz_order_id.ToString());
            if (instanceInfo.CurrentNodeId == request.node_id)
            {
                throw new BusinessException("退回节点与当前节点不可一致");
            }
            else if (instanceInfo.CurrentNodeId == instanceInfo.EndNodeId)
            {
                throw new BusinessException("审批完成单据不可退回");
            }

            return await _jjFlowActionSendBack.SendBack(request, instanceInfo, GetUserId());
        }

        public async Task<PageListSearchResultVM<JJInstanceViewModel>> GetInstancePageList(JJInstanceSearchCondition searchCondition)
        {
            return await _jjfLowActionApprove.GetInstancePageList(searchCondition, GetUserId());
        }

        public async Task<UserPowerResponse> CheckUserPower(CheckQueryRequest request)
        {
            request.user_id = GetUserId();
            return await _jjfLowActionApprove.CheckUserPower(request);
        }

        # region 同步飞书三方审批

        private readonly Dictionary<string, Func<JjFlowInstanceVM, JJFlowNodeReferenceVM, List<JJFlowNodeReferenceVM>, List<EmpInfo>, string, string, Task<List<FeiShuTripartiteTask>>>> _generateTasksFuncDict;

        public async Task SyncFeiShu(int instanceId, int? transferEmpId = null)
        {
            var instance = await _jjFlowInstanceService.GetById(instanceId);
            if (!JJFlowInstanceStatusConst.List.Contains(instance.Status))
            {
                throw new BusinessException($"审批实例[{instanceId}]: 状态异常[{instance.Status}]");
            }

            var template = await _jjFlowTemplateService.GetTemplateById(instance.TemplateId);
            if (!template.is_push_feishu)
            {
                return;
            }

            var feiShuExternalInstance = await GenerateFeiShuExternalInstance(template, instance, transferEmpId);
            var result = (await (await _openApiHttpClient.PostAsync(OpenApis.SyncExternalInstancesApi, new StringContent(feiShuExternalInstance.ToJson(), Encoding.UTF8, "application/json")))
                    .EnsureSuccessStatusCode()
                    .Content.ReadAsStringAsync())
                .ToObject<BaseOAResponse<object>>();

            if (result.Code != OAApiResultCode.Ok)
            {
                throw new Exception(result.Msg);
            }
        }

        private async Task<TripartiteApproveInput> GenerateFeiShuExternalInstance(JjFlowTemplateVM template, JjFlowInstanceVM instance, int? transferEmpId)
        {
            var nodeReferences = await _jjFlowNodeReferenceService.GetListByInstanceId(instance.Id);
            var instanceEmps = await _jjFlowInstanceEmpService.GetInstanceUserInfo(instance.Id, instance.TemplateId);
            var currentNodeReference = nodeReferences.First(x => x.NodeId == instance.CurrentNodeId);
            var link = await GetLink(template, instance.BizOrderId);
            var tripartiteApproveInput = new TripartiteApproveInput
            {
                modular_key = instance.ModularKey,
                instance_id = instance.Id.ToString(),
                links = new Links
                {
                    pc_link = link,
                    mobile_link = link
                },
                title = template.TemplateName,
                form = await GenerateForm(instance),
                user_id = (await _erpaUserRepository.GetById(instance.CreateUserId)).union_id,
                start_time = new DateTimeOffset(instance.CreateTime).ToUnixTimeMilliseconds(),
                update_time = new DateTimeOffset(instance.UpdateTime).ToUnixTimeMilliseconds(),
                end_time = JJFlowInstanceStatusConst.EndList.Contains(instance.Status) ? new DateTimeOffset(instance.UpdateTime).ToUnixTimeMilliseconds() : 0,
                status = JJFlowInstanceStatusConst.FeiShuInstanceStatusMapping[instance.Status],
                task_list = await (transferEmpId.HasValue
                    ? GenerateTasksWhenTransfer(instanceEmps, transferEmpId.Value, link, template.TemplateName)
                    : _generateTasksFuncDict[instance.Status].Invoke(instance, currentNodeReference, nodeReferences, instanceEmps, link, template.TemplateName))
            };

            if (instance.Status == JJFlowInstanceStatusConst.Reject || instance.Status == JJFlowInstanceStatusConst.Approved)
            {
                tripartiteApproveInput.Comment = await GetComment(instance.BizOrderId, instance.ModularKey);
            }

            return tripartiteApproveInput;
        }

        private async Task<string> GetLink(JjFlowTemplateVM template, string bizOrderId)
        {
            var function = await _functionRepository.GetFirstAsync(x => x.id == template.DetailPageId);
            var systemCodeEnum = (JJSystemCodeEnum)Convert.ToInt16(function.supplier_flag);
            var webDomains = _configuration.GetSection("WebDomain").Get<Dictionary<string, string>>();
            var webDomain = webDomains[systemCodeEnum.ToString()];
            return $"{webDomain}{function.path.TrimStart('/')}?{string.Format(template.DetailPageParameterKey, bizOrderId)}";
        }

        private async Task<List<Form>> GenerateForm(JjFlowInstanceVM instance)
        {
            var forms = new List<Form>();
            var dictCodes = await _jjFlowDicCodeService.GetListByTemplateId(instance.TemplateId);
            dictCodes = dictCodes.Where(x => x.is_push_feishu && x.deleted == 0).OrderBy(x => x.sort_number).ToList();
            if (dictCodes.Count > 0)
            {
                var instanceForms = await _jjFlowInstanceFormRepository.GetListByInstanceId(instance.Id);
                dictCodes.ForEach(dictCode =>
                {
                    forms.Add(new Form
                    {
                        name = dictCode.dictcode_name,
                        value = instanceForms.FirstOrDefault(x => x.form_key == dictCode.dictcode_key)?.form_value
                    });
                });
            }

            return forms;
        }

        private async Task<List<FeiShuTripartiteTask>> GenerateTasksWhenPending(JjFlowInstanceVM instance, JJFlowNodeReferenceVM currentNodeReference, List<JJFlowNodeReferenceVM> nodeReferences, List<EmpInfo> instanceEmps, string link, string title)
        {
            var tasks = new List<FeiShuTripartiteTask>();
            // 获取下一级节点相关
            var nextNodeReference = nodeReferences.First(x => x.Sequence == currentNodeReference.Sequence + 1);
            var nextNode = await _jJFlowNodeService.GetNodeById(nextNodeReference.NodeId);
            var nextNodeEmps = instanceEmps.FindAll(x => x.node_id == nextNodeReference.NodeId);
            // 是否会签并且存在完成
            var isCountersignAndExistComplete = false;
            // 如果节点为会签并且节点流程存在已完成,则无需处理下一节点未完成节点相关,因为第一次到该节点时已经同步过待办task了
            if ((JJFlowNodeEmpTypeEnum)nextNode.emp_type == JJFlowNodeEmpTypeEnum.AndNode && nextNodeEmps.Any(x => x.is_complete == 1))
            {
                nextNodeEmps = nextNodeEmps.FindAll(x => x.is_complete == 1);
                isCountersignAndExistComplete = true;
            }

            tasks.AddRange(nextNodeEmps.Select(x => new FeiShuTripartiteTask
            {
                task_id = x.id.ToString(),
                user_id = x.union_id.ToString(),
                links = new Links
                {
                    pc_link = link,
                    mobile_link = link
                },
                title = title,
                create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                end_time = x.is_complete == 1 ? new DateTimeOffset(x.update_time).ToUnixTimeMilliseconds() : 0,
                status = x.is_complete == 0 ? FeiShuFlowTaskStatusConst.Pending : FeiShuFlowTaskStatusConst.Approved
            }));

            // 当下一级节点 为会签并且节点流程存在已完成,则无需处理当前节点相关,因为第一次到该节点时已经同步过 完成/Down task了
            if (!isCountersignAndExistComplete)
            {
                var minSequence = nodeReferences.Min(x => x.Sequence);
                // 当前节点不是最小节点(即起始发起审批节点)时, 获取当前节点相关
                if (minSequence != currentNodeReference.Sequence)
                {
                    var currentNode = await _jJFlowNodeService.GetNodeById(instance.CurrentNodeId);
                    var currentNodeEmps = instanceEmps.FindAll(x => x.node_id == instance.CurrentNodeId);
                    if ((JJFlowNodeEmpTypeEnum)currentNode.emp_type == JJFlowNodeEmpTypeEnum.AndNode)
                    {
                        currentNodeEmps = currentNodeEmps.FindAll(x => x.is_complete == 1 && x.user_id == instance.UpdateUserId);
                    }

                    tasks.AddRange(currentNodeEmps.Select(x => new FeiShuTripartiteTask
                    {
                        task_id = x.id.ToString(),
                        user_id = x.union_id.ToString(),
                        links = new Links
                        {
                            pc_link = link,
                            mobile_link = link
                        },
                        title = title,
                        create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                        update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                        end_time = x.is_complete == 1 ? new DateTimeOffset(x.update_time).ToUnixTimeMilliseconds() : 0,
                        status = x.is_complete == 1 ? FeiShuFlowTaskStatusConst.Approved : FeiShuFlowTaskStatusConst.Done
                    }));
                }
            }

            tasks.AddRange(await GenerateTasksWhenHasAutomation(instance, currentNodeReference, nodeReferences, instanceEmps, link, title));
            return tasks;
        }

        private async Task<List<FeiShuTripartiteTask>> GenerateTasksWhenReject(JjFlowInstanceVM instance, JJFlowNodeReferenceVM currentNodeReference, List<JJFlowNodeReferenceVM> nodeReferences, List<EmpInfo> instanceEmps, string link, string title)
        {
            var currentNodeIncompleteEmps = instanceEmps.FindAll(x => x.node_id == currentNodeReference.NodeId && x.is_complete == 0);
            return currentNodeIncompleteEmps.Select(x => new FeiShuTripartiteTask
                {
                    task_id = x.id.ToString(),
                    user_id = x.union_id.ToString(),
                    links = new Links
                    {
                        pc_link = link,
                        mobile_link = link
                    },
                    title = title,
                    create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    end_time = new DateTimeOffset(instance.UpdateTime).ToUnixTimeMilliseconds(),
                    status = x.user_id == instance.UpdateUserId ? FeiShuFlowTaskStatusConst.Rejected : FeiShuFlowTaskStatusConst.Done
                })
                .Union(await GenerateTasksWhenHasAutomation(instance, currentNodeReference, nodeReferences, instanceEmps, link, title))
                .ToList();
        }

        private async Task<List<FeiShuTripartiteTask>> GenerateTasksWhenApproved(JjFlowInstanceVM instance, JJFlowNodeReferenceVM currentNodeReference, List<JJFlowNodeReferenceVM> nodeReferences, List<EmpInfo> instanceEmps, string link, string title)
        {
            var prevNodeReference = nodeReferences.First(x => x.Sequence == currentNodeReference.Sequence - 1);
            var prevNode = await _jJFlowNodeService.GetNodeById(prevNodeReference.NodeId);
            var prevNodeEmps = instanceEmps.FindAll(x => x.node_id == prevNodeReference.NodeId);
            if ((JJFlowNodeEmpTypeEnum)prevNode.emp_type == JJFlowNodeEmpTypeEnum.AndNode)
            {
                prevNodeEmps = prevNodeEmps.FindAll(x => x.is_complete == 1 && x.user_id == instance.UpdateUserId);
            }

            return prevNodeEmps.Select(x => new FeiShuTripartiteTask
                {
                    task_id = x.id.ToString(),
                    user_id = x.union_id.ToString(),
                    links = new Links
                    {
                        pc_link = link,
                        mobile_link = link
                    },
                    title = title,
                    create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    end_time = new DateTimeOffset(instance.UpdateTime).ToUnixTimeMilliseconds(),
                    status = x.is_complete == 1 ? FeiShuFlowTaskStatusConst.Approved : FeiShuFlowTaskStatusConst.Done
                })
                .Union(await GenerateTasksWhenHasAutomation(instance, prevNodeReference, nodeReferences, instanceEmps, link, title))
                .ToList();
        }

        private async Task<List<FeiShuTripartiteTask>> GenerateTasksWhenRecall(JjFlowInstanceVM instance, JJFlowNodeReferenceVM currentNodeReference, List<JJFlowNodeReferenceVM> nodeReferences, List<EmpInfo> instanceEmps, string link, string title)
        {
            var nextNodeReference = nodeReferences.First(x => x.Sequence == currentNodeReference.Sequence + 1);
            var nextNodeIncompleteEmps = instanceEmps.FindAll(x => x.node_id == nextNodeReference.NodeId && x.is_complete == 0);
            return nextNodeIncompleteEmps.Select(x => new FeiShuTripartiteTask
            {
                task_id = x.id.ToString(),
                user_id = x.union_id.ToString(),
                links = new Links
                {
                    pc_link = link,
                    mobile_link = link
                },
                title = title,
                create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                end_time = new DateTimeOffset(instance.UpdateTime).ToUnixTimeMilliseconds(),
                status = FeiShuFlowTaskStatusConst.Done
            }).ToList();
        }

        private async Task<List<FeiShuTripartiteTask>> GenerateTasksWhenTransfer(List<EmpInfo> instanceEmps, int transferEmpId, string link, string title)
        {
            var tasks = new List<FeiShuTripartiteTask>();

            // 转交后新的Emp
            var afterTransferEmp = instanceEmps.First(x => x.source_emp_id == transferEmpId);
            if (afterTransferEmp.is_complete == 0)
            {
                tasks.Add(new FeiShuTripartiteTask
                {
                    task_id = afterTransferEmp.id.ToString(),
                    user_id = afterTransferEmp.union_id,
                    links = new Links
                    {
                        pc_link = link,
                        mobile_link = link
                    },
                    title = title,
                    create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    status = FeiShuFlowTaskStatusConst.Pending
                });
            }

            // 备份Emp(即转交前的Emp)
            var bakEmp = await _flowInstanceEmpBakRepository.GetById(transferEmpId);
            tasks.Add(new FeiShuTripartiteTask
            {
                task_id = bakEmp.id.ToString(),
                user_id = bakEmp.union_id,
                links = new Links
                {
                    pc_link = link,
                    mobile_link = link
                },
                title = title,
                create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                status = FeiShuFlowTaskStatusConst.Done
            });

            return tasks;
        }

        // 当历史存在自动操作时, 需要构建历史emp对应的task
        private async Task<List<FeiShuTripartiteTask>> GenerateTasksWhenHasAutomation(JjFlowInstanceVM instance, JJFlowNodeReferenceVM processedNodeReference, List<JJFlowNodeReferenceVM> nodeReferences, List<EmpInfo> instanceEmps, string link, string title)
        {
            // 已处理节点前的
            var beforeProcessedNodeIds = nodeReferences.Where(x => x.Sequence < processedNodeReference.Sequence && x.Sequence != 0).Select(x => x.NodeId).ToList();
            var trackNodeIds = beforeProcessedNodeIds.Union(new[] { processedNodeReference.NodeId });
            var tracks = await _jjFlowTrackService.GetListAsync(x => x.instance_id == instance.Id && trackNodeIds.Contains(x.node_id));
            if (!tracks.Any(x => x.remark?.Contains("自动同意") ?? false))
            {
                return new List<FeiShuTripartiteTask>();
            }

            return instanceEmps.Where(x => beforeProcessedNodeIds.Contains(x.node_id)).Select(x => new FeiShuTripartiteTask
            {
                task_id = x.id.ToString(),
                user_id = x.union_id.ToString(),
                links = new Links
                {
                    pc_link = link,
                    mobile_link = link
                },
                title = title,
                create_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                update_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                end_time = x.is_complete == 0 ? new DateTimeOffset(instance.UpdateTime).ToUnixTimeMilliseconds() : new DateTimeOffset(x.update_time).ToUnixTimeMilliseconds(),
                status = x.is_complete == 0 ? FeiShuFlowTaskStatusConst.Done : FeiShuFlowTaskStatusConst.Approved
            }).ToList();
        }

        private async Task<string> GetComment(string bizOrderId, string modularKey)
        {
            var flowTracks = await _jjfLowActionCommon.GetFlowTrackList(bizOrderId, modularKey);
            return flowTracks.OrderByDescending(x => x.create_time).FirstOrDefault()?.remark;
        }

        # endregion
    }
}